package com.atxmf.test.JavaFoundation.queuetest;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/*
题目：一个初始值为0的变量，两个线程对其交替操作，一个加1一个减1，来5轮
    伴随着某种情况，中断和虚假唤醒是有可能发生的，所以wait()/await()这种方法要放在一个循环里面。

    synchronized和lock的区别。
    1：synchronized关键字是属于JVM层面的
       lock是具体的类(java.util.concurrent.locks.Lock)是api层面的锁
    2：synchronized不需要用户手动去释放锁，当synchronized代码块执行完后系统会自动让线程释放锁的占用。
        lock则一定要unlock();lock/unlock跟try/finally配合使用
    3：等待是否可中断
       synchronized不可中断，除非抛出异常或者程序中断
        lock可以中断，1)设置超时方法tryLock(long time,TimeUnit unit)
        2)lockInterruptibly()放在代码中，调用interrupt()方法可中断。
    4：synchronized非公平锁
        lock两者都可以，默认为非公平锁
    5：锁绑定多个条件Condition
        synchronized没有
        lock用来实现分组唤醒需要唤醒的线程们，可以精确唤醒，而不是像synchronized要么随机唤醒一个要么全部唤醒。
 */
class ShareData{
    private int number = 0;
    private Lock lock = new ReentrantLock();
    private Condition condition =  lock.newCondition();
    public void increment()throws Exception{
        lock.lock();
        try{
            while (number != 0){
                //等待，不能生产
                condition.await();
                System.out.println(Thread.currentThread().getName()+"\t ==生产者等待");

            }
            //干活
            number++;
            System.out.println(Thread.currentThread().getName()+"\t =="+number);
            //3.通知唤醒
            condition.signalAll();
        }finally {
            lock.unlock();
        }
    }

    public void decrement()throws Exception{
        lock.lock();
        try{
            while (number == 0){
                //等待，不能消费
                condition.await();
                System.out.println(Thread.currentThread().getName()+"\t ==消费者等待");
            }
            //干活
            number--;
            System.out.println(Thread.currentThread().getName()+"\t =="+number);
            //3.通知唤醒
            condition.signalAll();
        }finally {
            lock.unlock();
        }
    }
}
public class ProdConsumer_TraditionDemo {
    public static void main(String[] args) {
        ShareData shareData = new ShareData();
        new Thread(()->{
            for (int i = 1; i <=5 ; i++) {
                try {
                    shareData.increment();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        },"AAA").start(); new Thread(()->{
            for (int i = 1; i <=5 ; i++) {
                try {
                    shareData.decrement();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        },"BBB").start();
    }

}
